import breve
import random
			
class Controller(breve.Control):
	def __init__(self):
		breve.Control.__init__(self)
		self.setBackgroundColor(breve.vector())
		self.enableLighting()
		self.env = Room(breve.vector(20, 0, 20), 8, [], [], [84, 0])
		
	def iterate(self):
		breve.Control.iterate(self)
		self.updateNeighbors()

	def catchKeyXDown(self):
		exitBots = self.env.fetch.some(ExitBot, 20)
		while len(exitBots) > 0:
			exitBots.pop().leaveRoom()
	
	def catchKey1Down(self):
		self.env.placeBots([ExitBot], [50])

	def catchKey2Down(self):
		self.env.placeBots([VectorBot, ExitBot], [10, 20])
		
	def catchKeyKDown(self):
		exitBots = self.env.fetch.all(VectorBot)
		while len(exitBots) > 0: breve.deleteInstance(exitBots.pop())

class VectorBot(breve.Mobile):
	def __init__(self):
		breve.Mobile.__init__(self)
		self.handleCollisions('VectorBot', 'botCollision')
		self.enablePhysics()

	def iterate(self):
		breve.Mobile.iterate(self)
		self.neighborList = self.getNeighbors()
		
	def botCollision(self):
		self.setColor(breve.randomExpression(breve.vector(0, 1, 0)))

class ExitBot(VectorBot):
	def __init__(self):
		VectorBot.__init__(self)
		self.setColor(breve.randomExpression(
			breve.vector(0, 0, .9)) + breve.vector(0, 0, .1))
		self.getOut = False
		self.panic = 9
		self.discust = 10
		self.handleCollisions('ExitBot', 'botCollision')
		
	def iterate(self):
		VectorBot.iterate(self)
		if self.getOut:
			self.filterNeighbors([VectorBot])
			self.setVelocity((self.exit - self.getLocation()).normalize() * self.panic)
		else:
			self.filterNeighbors([VectorBot, BlackHole])
			self.setVelocity(self.getVelocity() + (breve.randomExpression(
				breve.vector(2, 0, 2)) - breve.vector(1, 0, 1)).normalize())
		if len(self.neighborList) > 0: self.applyAvoidance()
		
	def filterNeighbors(self, types):
		bots = []
		while len(self.neighborList) > 0:
			neighbor = self.neighborList.pop()
			for i in range(0, len(types)):
				if isinstance(neighbor, types[i]):
					bots.append(neighbor)
					break 
		self.neighborList = bots			
		
	def applyAvoidance(self):
		while len(self.neighborList) > 0:
			self.setVelocity(self.getVelocity() + (self.getLocation() - 
				self.neighborList.pop().getLocation()).normalize() * self.discust)
	
	def unitVector(self, v):
		unitVector = breve.vector(v[0] / abs(v[0]), 0, v[2] / abs(v[2]))
			
	def leaveRoom(self):
		self.getOut = True
		self.setColor(breve.randomExpression(
			breve.vector(.9, 0, 0)) + breve.vector(.1, 0, 0))
					
class Room(breve.Real):
	def __init__(self, dim, unit, botTypes, botCounts, exit):
		breve.Real.__init__(self)
		self.unit = unit
		self.width = dim[0]
		self.height = dim[2]
		self.exit = self.exit = breve.vector(exit[0], unit / 2, -exit[1])
		self.getController().pointCamera(
			breve.vector(self.width * unit / 2, 0, -self.height * unit / 2), 
			breve.vector(0, 200, self.height * unit))
		
		for x in range(0, self.width):
			Wall(breve.vector(x * unit + unit / 2, unit / 2, 0), 
				 breve.vector(unit, unit, .1))
			Wall(breve.vector(x * unit + unit / 2, unit / 2, -self.height * unit), 
				 breve.vector(unit, unit, .1))
		
		for z in range(0, self.height):
			Wall(breve.vector(0, unit / 2, -z * unit - unit / 2), 
				 breve.vector(.1, unit, unit))
			Wall(breve.vector(self.width * unit, unit / 2, -z * unit - unit / 2), 
				 breve.vector(.1, unit, unit))

		#for z in range(0, self.height):
			#for x in range(0, self.width):
				#Ground(breve.vector(x * unit + unit / 2, 0, -z * unit - unit / 2), 
					   #breve.vector(unit, .1, unit))
				
		Ground(breve.vector((self.width / 2) * unit, 0, -(self.height / 2) * unit), 
					   breve.vector(self.width * unit, .1, self.height * unit))	
		
		botCount = 0
		for c in range(0, len(botCounts)):
			botCount += botCounts[c]
		
		if botCount > self.width * self.height:
			print "Too many bots!"
		self.placeBots(botTypes, botCounts)
		
		BlackHole(unit).move(self.exit)
		self.fetch = Fetcher(
			breve.vector(self.width * unit / 2, -unit / 2, 
						-self.height * unit / 2), 
			max(self.width, self.height) * unit)

	def placeBots(self, botTypes, botCounts):
		positions = []
		positionCount = self.width * self.height
		
		for i in range(0, positionCount):
			positions.append(True)

		while len(botCounts) > 0:
			while True:
				spot = random.randint(0, positionCount - 1)
				if positions[spot]: break
				
			positions[spot] = False	
			bot = botTypes[0]()
			bot.move(breve.vector(
				int(spot % self.height) * self.unit + self.unit / 2, self.unit / 2, 
			   -int(spot / self.height) * self.unit - self.unit / 2))
			bot.unit = self.unit
			bot.setShape(breve.createInstances(breve.Cube, 1).initWith(
				breve.vector(self.unit - 1, self.unit - 1, self.unit - 1)))
			bot.setNeighborhoodSize(self.unit * 2)
			
			if isinstance(bot, ExitBot):
				bot.exit = self.exit
				bot.setNeighborhoodSize(self.unit + 1)
				bot.setShape(breve.createInstances(breve.Sphere, 1).initWith(self.unit / 2 - 1))
			
			botCounts[0] -= 1
			if botCounts[0] == 0:
				botCounts.pop(0)
				botTypes.pop(0)
			
	def getOut(self):
		self.exit = True
		self.setColor(breve.vecter(1, 0, 0))
		self.discust = 1
class Obstruction(breve.Stationary):
	def __init__(self, position, dimension, color):
		breve.Stationary.__init__(self)
		self.setTexture(-1)
		self.setShape(breve.createInstances(breve.Cube, 1).initWith(dimension))
		self.setColor(color)
		self.move(position)
	
class Wall(Obstruction):
	def __init__(self, position, dimension):
		Obstruction.__init__(self, position, dimension, breve.vector(1.0, 1.0, 1.0))
		#self.setBitmapTransparency(0.5)	
		
class Ground(Obstruction):
	def __init__(self, position, dimension):
		Obstruction.__init__(self, position, dimension, breve.vector(0.0, 0.3, 0.0))
		#self.setBitmapTransparency(0.5)
		
class BlackHole(breve.Mobile):
	def __init__(self, unit):
		breve.Mobile.__init__(self)
		self.setNeighborhoodSize(unit / 2)
		self.setColor(breve.vector(0, 0, 0))	
		
	def iterate(self):	
		breve.Mobile.iterate(self)
		self.neighborList = self.getNeighbors()
		while len(self.neighborList) > 0: 
			breve.deleteInstance(self.neighborList.pop())

class Fetcher(breve.Mobile):
	def __init__(self, position, sight):
		breve.Mobile.__init__(self)
		self.move(position)
		self.setNeighborhoodSize(sight)
	
	def iterate(self):
		breve.Mobile.iterate(self)
		self.neighborList = self.getNeighbors()
	
	def all(self, instance):
		return self.some(instance, len(self.neighborList))
		
	def some(self, instance, count):
		instances = []
		while len(self.neighborList) > 0 and count > 0:
			bot = self.neighborList.pop()
			if isinstance(bot, instance):
				instances.append(bot)
				count -= 1
		return instances
		
Controller()